package rs.frenjoynet.core.core.db;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.SQLQuery;
import org.hibernate.cfg.Configuration;

import java.util.List;
import java.util.Date;

import cz.atria.common.lang.Util;


/**
 * Created by IntelliJ IDEA.
 * User: ppopovic
 * Date: 23.10.2009.
 * Time: 12.59.47
 * To change this template use File | Settings | File Templates.
 */
public class MySqlHibDBBrokerImpl implements DBBroker
{
	private Session session;
	private Transaction transaction;
	private SessionFactory sessionFactory;
	private String configurationPath;

	private static final String DefaultPath = "rs/frenjoynet/core/core/cfg/hibernate.cfg.xml";

	public MySqlHibDBBrokerImpl(String configurationPath)
	{
		this.configurationPath = configurationPath;
		sessionFactory = new Configuration().configure(configurationPath).buildSessionFactory();
	}

	public MySqlHibDBBrokerImpl(SessionFactory sessionFactory)
	{
		this.sessionFactory = sessionFactory;
	}

	public MySqlHibDBBrokerImpl()
	{
		this(DefaultPath);
	}

	public SessionFactory getSessionFactory()
	{
		return sessionFactory;
	}

	//	public static void main(String[] args)
//	{
//		Session session = null;
//
//		try
//		{
//			SessionFactory sessionFactory = new
//
//			Configuration().configure("rs/frenjoynet/core/core/cfg/hibernate.cfg.xml").buildSessionFactory();
//			session = sessionFactory.openSession();
//			Transaction tr = session.beginTransaction();
//			tr.begin();
//
//			Artist getArt = (Artist)session.get(Artist.class, new Integer(4));
//			System.out.println(getArt.toString() + "Inserting Record");
//			Artist artist = new Artist();
//			// artist.setId(1);
//			artist.setArtist("Pera Kojot");
//			artist.setDetails("dddd");
//
//			Integer i = (Integer)session.save(artist);
//			tr.commit();
//			System.out.println("Done" + i);
//		}
//		catch (Exception e)
//		{
//			System.out.println(e.getMessage());
//		}
//		finally
//		{
//			// Actual contact insertion will happen at this step
//			session.flush();
//			session.close();
//
//		}
//
//	}

	public synchronized void prepareSession(Boolean isTransaction)
	{
		try
		{
			session = sessionFactory.openSession();
			if (isTransaction)
			{
				transaction = session.beginTransaction();
				transaction.begin();
			}

		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	public synchronized void relaseSession(boolean isTransaction)
	{
		try
		{
			if (isTransaction && transaction != null && transaction.isActive())
			{
				transaction.commit();
			}
			if (session != null)
			{
				session.flush();
				session.close();
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}


	}

	@Override
	public <T> Object insert(Class<T> clazz, Object entity)
	{
		prepareSession(true);

		session.save(clazz.getName(), entity);

		relaseSession(true);
		return entity;  //To change body of implemented methods use File | Settings | File Templates.
	}

	@Override
	public <T> Object update(Class<T> clazz, Object entity)
	{
		prepareSession(true);

		session.update(entity);

		relaseSession(true);
		return entity;
	}

	@Override
	public <T> Object update(Class<T> clazz, String sql, Object... ids)
	{
		throw new RuntimeException("Not implemented!!");
	}

	@Override
	public int delete(String sql, Object... ids)
	{
		prepareSession(true);

		SQLQuery query = preparedSqlQuery(sql, ids);
		int count = query.executeUpdate();

		relaseSession(true);
		return count;
	}

	@Override
	public <T> List query(Class<T> clazz, String sql, Object... ids)
	{
		return query(clazz, 1, null, sql, ids);
	}

	@Override
	public <T> Object queryOne(Class<T> clazz, String sql, Object... ids)
	{
		List<T> result = query(clazz, 1, 1, sql, ids);
		if (!result.isEmpty())
			return (T)result.get(0);
		else
			return null;
	}

	@Override
	public <T> List query(Class<T> clazz, int first, Integer rowCount, String sql, Object... ids)
	{
		prepareSession(true);

		SQLQuery query = preparedSqlQuery(sql, ids);
		query.addEntity(clazz);
		query.setFirstResult(first);
		if (rowCount != null)
			query.setMaxResults(rowCount);
		List<T> result = query.list();
		
		relaseSession(true);
		return result;
	}

	@Override
	public <T> List pageQuery(Class<T> clazz, int page, int pageSize, String sql, Object... ids)
	{
		return query(clazz, (page - 1) * pageSize, pageSize, sql, ids);
	}

	private SQLQuery preparedSqlQuery(String sql, Object... ids)
	{
		SQLQuery query = session.createSQLQuery(sql);
		if (!Util.isEmpty(ids))
		{
			int i = 0;
			for (Object obj : ids)
			{
				// TODO ovo treba jos doraditi  , za razne tipove
				if (obj instanceof Integer)
				{
					query.setInteger(i, (Integer)obj);
				}
				else if (obj instanceof String)
				{
					query.setString(i, (String)obj);
				}
				else if (obj instanceof Date)
				{
					query.setDate(i, (Date)obj);
				}

				i++;
			}

		}
		return query;

	}
}
